﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;

namespace Malkafly.EFDorsal.BusinessLayer
{
    public class ProcessaTemplate
    {
        public List<EntidadeGenerica> Processa(Stream pXml, ref EntityConfiguracoes Configuracao)
        {
            #region Declarando as variaveis
            string EntitySet = string.Empty;
            string EntityType = string.Empty;
            string EntityContainer = string.Empty;
            string NamespaceProjeto = "Projeto.Demo";
            string NamespaceData = "Projeto.DataLayer";
            int CountArquivos = 0;
            #endregion

            StreamReader streamReader = new StreamReader(pXml);
            string xmlData = streamReader.ReadToEnd();
            streamReader.Close();
            XmlTextReader xmlReader = new XmlTextReader(new StringReader(xmlData));
            xmlReader.WhitespaceHandling = WhitespaceHandling.None;
            xmlReader.MoveToContent();

            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(xmlReader);

            XmlNodeList elementos = xmlDoc.GetElementsByTagName("edmx:ConceptualModels");

            List<EntidadeGenerica> listaClasse = new List<EntidadeGenerica>();
            foreach (XmlElement element in elementos)
            {
                string Schema = element.GetElementsByTagName("Schema")[0].Attributes["Namespace"].Value.ToString();

                XmlNode xmlEntityContainer = element.GetElementsByTagName("EntityContainer").Item(0);
                EntityContainer = xmlEntityContainer.Attributes["Name"].Value.ToString();
                Configuracao.EntityContainer = EntityContainer;

                int count = 0;
                foreach (XmlNode arrEntitySet in element.GetElementsByTagName("EntitySet"))
                {
                    count++;

                    EntitySet = arrEntitySet.Attributes["Name"].Value;
                    EntityType = arrEntitySet.Attributes["EntityType"].Value.Replace(Schema, string.Empty).Replace(".", string.Empty);

                    EntidadeGenerica template = new EntidadeGenerica();
                    template.EntityType = EntityType;
                    template.EntitySet = EntitySet;

                    foreach (XmlElement arrEntityType in element.GetElementsByTagName("EntityType"))
                    {
                        if (arrEntityType.Attributes["Name"].Value == EntityType)
                        {
                            string propertyKey = string.Empty;
                            List<EntityFields> listPropertys = new List<EntityFields>();
                            for (int i = 0; i < arrEntityType.ChildNodes.Count; i++)
                            {
                                EntityFields objProperty = new EntityFields();
                                if (arrEntityType.GetElementsByTagName("Key")[i] != null)
                                {
                                    propertyKey = arrEntityType.GetElementsByTagName("PropertyRef").Item(0).Attributes["Name"].Value;
                                }


                                if (arrEntityType.GetElementsByTagName("Property")[i] != null)
                                {
                                    objProperty.PropertyName = arrEntityType.GetElementsByTagName("Property")[i].Attributes["Name"].Value;
                                    objProperty.PropertyType = arrEntityType.GetElementsByTagName("Property")[i].Attributes["Type"].Value;

                                    if (arrEntityType.GetElementsByTagName("Property")[i].Attributes["Nullable"] != null)
                                    {
                                        objProperty.isNullable = (arrEntityType.GetElementsByTagName("Property")[i].Attributes["Nullable"].Value == "true");
                                    }
                                    if (arrEntityType.GetElementsByTagName("Property")[i].Attributes["MaxLength"] != null)
                                    {
                                        objProperty.MaxLength = Convert.ToInt32(arrEntityType.GetElementsByTagName("Property")[i].Attributes["MaxLength"].Value);
                                    }

                                    if (arrEntityType.GetElementsByTagName("Property")[i].Attributes["Name"].Value == propertyKey)
                                    {
                                        if (arrEntityType.GetElementsByTagName("Property")[i].Attributes["StoreGeneratedPattern"] != null)
                                        {
                                            objProperty.StoreGeneratedPattern = arrEntityType.GetElementsByTagName("Property")[i].Attributes["StoreGeneratedPattern"].Value;
                                        }
                                        objProperty.isKey = true;
                                    }
                                    listPropertys.Add(objProperty);
                                }

                            }
                            template.EntityProperty = listPropertys;
                        }
                    }
                    listaClasse.Add(template);
                }
                //GerarClass(listaClasse,configuracoes);

                CountArquivos++;
            }

            xmlReader.Close();
            return listaClasse;
        }



        public void GerarClass(List<EntidadeGenerica> item, EntityConfiguracoes confs)
        {
            foreach (EntidadeGenerica arrTemplate in item)
            {
                TextWriter novaClasse = new StreamWriter(confs.OutputFolder + "/" + arrTemplate.EntityType + ".cs");

                StringBuilder strSelect = new StringBuilder();
                strSelect.Append("using System;\n");
                strSelect.Append("using System.Collections.Generic;\n");
                strSelect.Append("using System.Linq;\n");
                strSelect.Append("using System.Text;\n");
                strSelect.Append("using " + confs.NamespaceData + ";\n\n");
                strSelect.Append("namespace " + confs.NamespaceProjeto + "\n");
                strSelect.Append("{\n");
                strSelect.Append("  public class BE" + arrTemplate.EntityType + " : Singleton<BE" + arrTemplate.EntityType + ">\n");
                strSelect.Append("  {\n");

                strSelect.Append("              " + GeraSelect(confs.EntityContainer, arrTemplate.EntityType, arrTemplate.EntitySet));
                strSelect.Append("              " + GeraSelectUnico(confs.EntityContainer, arrTemplate));
                strSelect.Append("              " + GeraInsert(arrTemplate, confs));
                strSelect.Append("              " + GeraDelete(confs.EntityContainer, arrTemplate));
                strSelect.Append("              " + GeraUpdate(arrTemplate, confs));

                strSelect.Append("  }\n");
                strSelect.Append("}\n");

                novaClasse.Write(strSelect.ToString());

                novaClasse.Close();
            }
        }
        private string GeraSelect(string EntityContainer, string EntityType, string EntitySet)
        {
            StringBuilder strSelect = new StringBuilder();
            strSelect.Append("public List<#EntityType#> Select()\n");
            strSelect.Append("{\n");
            strSelect.Append("    using (#EntityContainer# context = new #EntityContainer#())\n");
            strSelect.Append("    {\n");
            strSelect.Append("        #EntityType# obj#EntityType# = (from a in context.#EntitySet# select a).ToList();\n");
            strSelect.Append("        return obj#EntityType#;\n");
            strSelect.Append("    }\n");
            strSelect.Append("}\n");

            string strRetorno = strSelect.ToString();
            return strRetorno.Replace("#EntityType#", EntityType).Replace("#EntityContainer#", EntityContainer).Replace("#EntitySet#", EntitySet);
        }

        private string GeraSelectUnico(string EntityContainer, EntidadeGenerica item)
        {
            StringBuilder strSelect = new StringBuilder();
            strSelect.Append("public List<#EntityType#> Select(#Type# p#Key#)\n");
            strSelect.Append("{\n");
            strSelect.Append("    using (#EntityContainer# context = new #EntityContainer#())\n");
            strSelect.Append("    {\n");
            strSelect.Append("        #EntityType# obj#EntityType# = (from a in context.#EntitySet#\n");
            strSelect.Append("                          where a.#Key# == #Key#\n");
            strSelect.Append("                          select a).FirstOrDefault();\n");
            strSelect.Append("        return obj#EntityType#;\n");
            strSelect.Append("    }\n");
            strSelect.Append("}\n");

            string strRetorno = strSelect.ToString();
            return strRetorno.Replace("#EntityType#", item.EntityType).Replace("#EntityContainer#", EntityContainer).Replace("#EntitySet#", item.EntitySet).Replace("#Key#", item.EntityPropertyKey).Replace("#Type#", item.EntityPropertyKeyType);
        }

        private string GeraInsert(EntidadeGenerica item, EntityConfiguracoes confs)
        {
            StringBuilder strSelect = new StringBuilder();
            strSelect.Append("public #EntityKeyType# Select(");
            strSelect.Append(GeraParametrosInternos(item.EntityProperty));
            strSelect.Append(")\n");
            strSelect.Append("{\n");
            strSelect.Append("    using (#EntityContainer# context = new #EntityContainer#())\n");
            strSelect.Append("    {\n");
            strSelect.Append("      #EntityType# obj#EntityType# = new #EntityType#();\n\n");
            strSelect.Append("      ");
            foreach (EntityFields arrParametros in item.EntityProperty)
            {
                strSelect.Append("          obj#EntityType#." + arrParametros.PropertyType + " = " + "p" + arrParametros.PropertyName + ";\n");
            }
            strSelect.Append("      ");
            strSelect.Append("      context.SaveChanges(true);\n");
            strSelect.Append("      return obj#EntityType#." + item.EntityPropertyKey + ";\n");
            strSelect.Append("    }\n");
            strSelect.Append("}\n");

            string strRetorno = strSelect.ToString();
            return strRetorno.Replace("#EntityContainer#", confs.EntityContainer).Replace("#EntityKeyType#", item.EntityPropertyKeyType).Replace("#EntityType#", item.EntityType);
        }

        private string GeraUpdate(EntidadeGenerica item, EntityConfiguracoes confs)
        {
            StringBuilder strSelect = new StringBuilder();
            strSelect.Append("public #EntityKeyType# Update(");
            strSelect.Append(item.EntityPropertyKeyType.ToString() + " " + "p" + item.EntityPropertyKey.ToString() + ", ");
            strSelect.Append(GeraParametrosInternos(item.EntityProperty));
            strSelect.Append(")\n");
            strSelect.Append("{\n");
            strSelect.Append("    using (#EntityContainer# context = new #EntityContainer#())\n");
            strSelect.Append("    {\n");
            strSelect.Append("      #EntityType# obj#EntityType# = Select(" + item.EntityPropertyKey.ToString() + ");\n\n");
            strSelect.Append("      ");

            foreach (EntityFields arrParametros in item.EntityProperty)
            {
                strSelect.Append("          obj#EntityType#." + arrParametros.PropertyType + " = " + "p" + arrParametros.PropertyName + ";\n");
            }

            strSelect.Append("      ");
            strSelect.Append("      context.SaveChanges(true);\n");
            strSelect.Append("      return obj#EntityType#." + item.EntityPropertyKey + ";\n");
            strSelect.Append("    }\n");
            strSelect.Append("}\n");

            string strRetorno = strSelect.ToString();
            return strRetorno.Replace("#EntityContainer#", confs.EntityContainer).Replace("#EntityKeyType#", item.EntityPropertyKeyType).Replace("#EntityType#", item.EntityType);
        }

        private string GeraDelete(string EntityContainer, EntidadeGenerica item)
        {
            StringBuilder strSelect = new StringBuilder();
            strSelect.Append("public bool Insert(#Type# p#Key#)\n");
            strSelect.Append("{\n");
            strSelect.Append("    using (#EntityContainer# context = new #EntityContainer#())\n");
            strSelect.Append("    {\n");
            strSelect.Append("        #EntityType# obj#EntityType# = (from a in context.#EntitySet#\n");
            strSelect.Append("                          where a.#Key# == #Key#\n");
            strSelect.Append("                          select a).FirstOrDefault();\n");
            strSelect.Append("      return context.SaveChanges(true);\n");
            strSelect.Append("    }\n");
            strSelect.Append("}\n");

            string strRetorno = strSelect.ToString();
            return strRetorno.Replace("#EntityType#", item.EntityType).Replace("#EntityContainer#", EntityContainer).Replace("#EntitySet#", item.EntitySet).Replace("#Key#", item.EntityPropertyKey).Replace("#Type#", item.EntityPropertyKeyType);
        }

        private string GeraParametrosInternos(List<EntityFields> itens)
        {
            string strRetorno = string.Empty;
            if (itens.Count != 0)
            {
                foreach (EntityFields arrParametros in itens)
                {
                    strRetorno += ", " + arrParametros.PropertyType + " " + "p" + arrParametros.PropertyName;
                }
                return strRetorno.Substring(1);
            }
            else
            {
                return string.Empty;
            }
        }

    }
}
